package c2.cross.business.championrace.sub;

import c2.cross.business.base.CrossSubModule;
import c2.cross.business.championrace.ChampionRaceModule;
import c2.cross.business.championrace.handler.*;
import cate.common.table.d.GDChampionRace;
import cate.game.event.championrace.ChampionRaceTimerEvent;
import cate.game.framework.timer.FIFOTimerSelector;
import cate.game.framework.timer.FIFOTimerTask;
import cate.game.framework.timer.TimerTask;
import cate.game.pvp.championrace.timer.ChampionRaceTimerTask;
import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
public class ChampionRaceTimerModule extends CrossSubModule<ChampionRaceModule> {
    private ChampionRaceSettingHandlerSelector handlerSelector;
    private FIFOTimerSelector taskSelector;

    @Override
    public void initDependent() {
        taskSelector = new FIFOTimerSelector(buildTimerTaskList(), () -> GDChampionRace.WHOLE_SEASON_TIME);
        handlerSelector = new ChampionRaceSettingHandlerSelector(
                new ChampionRaceControlSettingHandler(parent),
                new ChampionRaceBetRwdSettingHandler(parent),
                new ChampionRaceGroupSettingHandler(parent),
                new ChampionRaceKoSettingHandler(parent),
                new ChampionRaceRankRwdSettingHandler(parent),
                new ChampionRaceReadySettingHandler(parent),
                new ChampionRaceTrialSettingHandler(parent),
                new ChampionRaceFinalSettingHandler(parent)
        );
    }

    public ChampionRaceTimerEvent createTimerEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent timerEvent = new ChampionRaceTimerEvent();
        timerEvent.setSeason(setting.getSpec().getSeason());
        timerEvent.setExecutedTime(setting.getTriggerTimeMs());
        timerEvent.setEventType(setting.getEventType());
        switch (timerEvent.getEventType()) {
            case OPEN:
                timerEvent.setOpenEvent(buildOpenEvent(setting));
                break;
            case SWITCH:
                timerEvent.setSwitchEvent(buildSwitchEvent(setting));
                break;
            case TRIAL_GROUP:
                timerEvent.setTrialGroupEvent(buildTrialGroupEvent(setting));
                break;
            case RANK_SETTLE:
                timerEvent.setRankSettleEvent(buildRankSettleEvent(setting));
                break;
            case INVITATION:
                timerEvent.setInvitationEvent(buildInvitationEvent(setting));
                break;
            case TRIAL:
                timerEvent.setTrialEvent(buildTrialEvent(setting));
                break;
            case KO_GROUP:
                timerEvent.setKoGroupEvent(buildKoGroupEvent(setting));
                break;
            case KO:
                timerEvent.setKoEvent(buildKoEvent(setting));
                break;
            case FINAL_GROUP:
                timerEvent.setFinalGroupEvent(buildFinalGroupEvent(setting));
                break;
            case FINAL:
                timerEvent.setFinalEvent(buildFinalEvent(setting));
                break;
            case RANK_SWITCH:
                timerEvent.setRankSwitchEvent(buildRankSwitchEvent(setting));
                break;
            case SHOW:
                timerEvent.setShowEvent(buildShowEvent(setting));
                break;
            case REST:
                timerEvent.setRestEvent(buildRestEvent(setting));
                break;
            default:
                break;
        }
        return timerEvent;
    }

    private ChampionRaceTimerEvent.RestEvent buildRestEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.RestEvent restEvent = new ChampionRaceTimerEvent.RestEvent();
        restEvent.setSpec(setting.getSpec());
        return restEvent;
    }

    private ChampionRaceTimerEvent.ShowEvent buildShowEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.ShowEvent showEvent = new ChampionRaceTimerEvent.ShowEvent();
        showEvent.setSpec(setting.getSpec());
        return showEvent;
    }

    private ChampionRaceTimerEvent.RankSettleEvent buildRankSettleEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.RankSettleEvent rankSettleEvent = new ChampionRaceTimerEvent.RankSettleEvent();
        rankSettleEvent.setSpec(setting.getSpec());
        return rankSettleEvent;
    }

    private ChampionRaceTimerEvent.InvitationEvent buildInvitationEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.InvitationEvent invitationEvent = new ChampionRaceTimerEvent.InvitationEvent();
        invitationEvent.setSpec(setting.getSpec());
        return invitationEvent;
    }

    private ChampionRaceTimerEvent.RankSwitchEvent buildRankSwitchEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.RankSwitchEvent rankSwitchEvent = new ChampionRaceTimerEvent.RankSwitchEvent();
        rankSwitchEvent.setSpec(setting.getSpec());
        return rankSwitchEvent;
    }

    private ChampionRaceTimerEvent.FinalEvent buildFinalEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.FinalEvent finalEvent = new ChampionRaceTimerEvent.FinalEvent();
        finalEvent.setSpec(setting.getSpec());
        return finalEvent;
    }

    private ChampionRaceTimerEvent.FinalGroupEvent buildFinalGroupEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.FinalGroupEvent finalGroupEvent = new ChampionRaceTimerEvent.FinalGroupEvent();
        finalGroupEvent.setSpec(setting.getSpec());
        return finalGroupEvent;
    }

    private ChampionRaceTimerEvent.KoEvent buildKoEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.KoEvent koEvent = new ChampionRaceTimerEvent.KoEvent();
        koEvent.setSpec(setting.getSpec());
        return koEvent;
    }

    private ChampionRaceTimerEvent.KoGroupEvent buildKoGroupEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.KoGroupEvent koGroupEvent = new ChampionRaceTimerEvent.KoGroupEvent();
        koGroupEvent.setSpec(setting.getSpec());
        return koGroupEvent;
    }

    private ChampionRaceTimerEvent.TrialEvent buildTrialEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.TrialEvent trialEvent = new ChampionRaceTimerEvent.TrialEvent();
        trialEvent.setSpec(setting.getSpec());
        return trialEvent;
    }

    private ChampionRaceTimerEvent.TrialGroupEvent buildTrialGroupEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.TrialGroupEvent trialGroupEvent = new ChampionRaceTimerEvent.TrialGroupEvent();
        trialGroupEvent.setSpec(setting.getSpec());
        return trialGroupEvent;
    }

    private ChampionRaceTimerEvent.SwitchEvent buildSwitchEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.SwitchEvent switchEvent = new ChampionRaceTimerEvent.SwitchEvent();
        switchEvent.setSpec(setting.getSpec());
        switchEvent.setSwitchTime(setting.getTriggerTimeMs());
        switchEvent.setFromSeason(parent.getSeason());
        switchEvent.setToSeason(setting.getSpec().getSeason());
        return switchEvent;
    }

    private ChampionRaceTimerEvent.OpenEvent buildOpenEvent(ChampionRaceTimerTask.Setting setting) {
        ChampionRaceTimerEvent.OpenEvent openEvent = new ChampionRaceTimerEvent.OpenEvent();
        openEvent.setSpec(setting.getSpec());
        openEvent.setOpenTime(setting.getTriggerTimeMs());
        openEvent.setClosedTime(parent.getCloseTime());
        openEvent.setSeason(parent.getSeason());
        return openEvent;
    }

    protected LinkedList<FIFOTimerTask> buildTimerTaskList() {
        return parent.getTimerSettings()
                .stream()
                .map(setting -> new ChampionRaceTimerTask(
                        setting,
                        s -> parent.dispatchTimerEvent(s.getSpec(), createTimerEvent(s)),
                        setting1 -> {
                            AbstractChampionRaceSettingHandler selector = handlerSelector.select(setting1);
                            if (selector != null) {
                                return selector.runSettingFunction(setting1);
                            }
                            return true;
                        }))
                .collect(Collectors.toCollection(LinkedList::new));
    }

    @Override
    public void onInterval() {
        Optional.of(taskSelector)
                .map(selector -> selector.select(System.currentTimeMillis()))
                .ifPresent(TimerTask::run);
    }
}
